package org.jsola.hr.task;

import com.alibaba.fastjson.JSON;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.xxl.job.core.log.XxlJobLogger;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.jsola.admin.entity.GregorianCalendarDO;
import org.jsola.admin.entity.SiteDO;
import org.jsola.admin.query.GregorianCalendarQuery;
import org.jsola.common.DateKit;
import org.jsola.common.DateKit8;
import org.jsola.exception.ParamException;
import org.jsola.hr.common.DateUtils;
import org.jsola.hr.constant.PunchType;
import org.jsola.hr.constant.RuleType;
import org.jsola.hr.dao.IAttendPeopleMonthlyStatDAO;
import org.jsola.hr.dao.IAttendPeriodStatDAO;
import org.jsola.hr.dao.IAttendPlanDAO;
import org.jsola.hr.dao.IAttendPunchRecordDAO;
import org.jsola.hr.dto.AttendAdvancedDTO;
import org.jsola.hr.dto.attendrule.AttendRulePunchTimeAddDTO;
import org.jsola.hr.dto.attendschedule.AttendPeriodDTO;
import org.jsola.hr.dto.attendschedule.AttendShiftSaveDTO;
import org.jsola.hr.entity.*;
import org.jsola.hr.provider.IAdminProviderService;
import org.jsola.hr.provider.IGregorianCalendarProviderService;
import org.jsola.hr.query.*;
import org.jsola.hr.service.*;
import org.jsola.hr.vo.AttendNeedPunchVO;
import org.jsola.hr.vo.AttendPointTimeVO;
import org.jsola.hr.vo.StaffVO;
import org.jsola.user.core.TokenUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import tk.mybatis.mapper.entity.Example;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 统计前一日的考勤缺卡
 *
 * @author wxz
 */
@Slf4j
@Component
public class LackAttendTask {

    @Autowired
    private IAttendPlanDAO attendPlanDAO;
    @Autowired
    private IAttendPunchStaffService attendPunchStaffService;
    @Autowired
    private IAttendPunchDeptService attendPunchDeptService;
    @Autowired
    private IEmpDepService empDepService;
    @Autowired
    private IEmpInfoService empInfoService;
    @Autowired
    private IAttendWhitelistService attendWhitelistService;
    @Autowired
    private IAttendCalendarService attendCalendarService;
    @Autowired
    private IAttendPunchTimeService attendPunchTimeService;
    @Autowired
    private IAttendShiftService attendShiftService;
    @Autowired
    private IAttendPunchRecordService attendPunchRecordService;
    @Autowired
    private IAttendPunchRecordDAO attendPunchRecordDAO;
    @Autowired
    private IAttendPeopleMonthlyStatService attendPeopleMonthlyStatService;
    @Autowired
    private IAttendPeopleMonthlyStatDAO attendPeopleMonthlyStatDAO;
    @Autowired
    private IAdminProviderService adminProviderService;
    @Autowired
    private ICompanyService companyService;
    @Autowired
    private IAttendPeriodStatDAO attendPeriodStatDAO;
    @Autowired
    private IDepInfoService depInfoService;
    @Autowired
    private IGregorianCalendarProviderService gregorianCalendarProviderService;

    /**
     * 	统计前一日的考勤缺卡
     */
    @XxlJob("lackAttendTask")
    public ReturnT<String> lackAttendTask(String params) {
        XxlJobLogger.log("==========定时任务开始: 统计前一日的考勤缺卡");
        try {
            lackAttend();
        } catch (Exception e) {
            XxlJobLogger.log("==========定时任务失败: 统计前一日的考勤缺卡,失败原因 : {}", e.getMessage());
            return ReturnT.FAIL;
        }
        XxlJobLogger.log("==========定时任务结束: 统计前一日的考勤缺卡");
        return ReturnT.SUCCESS;
    }

    public void lackAttend() throws ParseException {
        // 统计缺卡
        log.info("缺卡 ---> 统计昨日的考勤缺卡");

        // 昨天
        String yesterdayStr = DateUtils.getPreDateByDate(DateFormatUtils.format(new Date(), "yyyy-MM-dd"));
        Date yesterday = null;
        try {
            yesterday = org.apache.commons.lang3.time.DateUtils.parseDate(yesterdayStr, "yyyy-MM-ddd");
        } catch (ParseException e) {
            e.printStackTrace();
        }

        String yearly = DateFormatUtils.format(yesterday, "yyyy");
        String monthly = DateFormatUtils.format(yesterday, "MM");
        String daily = DateFormatUtils.format(yesterday, "dd");
        String dateStr = DateFormatUtils.format(yesterday, "yyyy-MM-dd");

        // 查询所有的考勤规则
        Example example = new Example(AttendPlanDO.class);
        example.and()
                .andEqualTo("valid", true);
        List<AttendPlanDO> attendPlanList = attendPlanDAO.selectByExample(example);
        if (attendPlanList.size() <= 0) {
            return;
        }
        // 查询  查询出来的所有考勤规则所在的租户
        List<String> siteIdList = attendPlanList.stream().map(AttendPlanDO::getSiteId).distinct().collect(Collectors.toList());
        List<String> companyIdList = attendPlanList.stream().map(AttendPlanDO::getCompanyId).collect(Collectors.toList());
        List<SiteDO> siteList = adminProviderService.selectByIds(siteIdList);
        Map<String, SiteDO> siteMap = siteList.stream().collect(Collectors.toMap(SiteDO::getId, v -> v));
        List<CompanyDO> companyList = companyService.selectByIdsNotSiteId(companyIdList);
        Map<String, CompanyDO> companyMap = companyList.stream().collect(Collectors.toMap(CompanyDO::getId, v -> v));
        for (AttendPlanDO plan : attendPlanList) {
            CompanyDO company = companyMap.get(plan.getCompanyId());
            if(ObjectUtils.isEmpty(company)){
                continue;
            }
            SiteDO site = siteMap.get(plan.getSiteId());
            if(ObjectUtils.isEmpty(site) || site.getDeleted() ||
                    (site.getExpireDate() != null && site.getExpireDate().getTime() < System.currentTimeMillis())){
                continue;
            }
            Set<StaffVO> staffIds = new HashSet<>();
            // 查询考勤打卡参与人员
            Set<StaffVO> set1 = this.getStaffSetForPunchStaff(plan.getId(), plan.getSiteId());
            if (!CollectionUtils.isEmpty(set1)) {
                staffIds.addAll(set1);
            }
            // 查询考勤打卡参与部门
            Set<StaffVO> set2 = this.getStaffSetForPunchDep(plan.getId(), plan.getSiteId());
            if (!CollectionUtils.isEmpty(set2)) {
                staffIds.addAll(set2);
            }
            // 当前日期是否需要打卡
            AttendNeedPunchVO attendNeedPunchVO = attendCalendarService.isNeedPunchOfDaily(plan.getId(), dateStr, plan.getSiteId());
            // 遍历每一个打卡人员
            if (!CollectionUtils.isEmpty(staffIds)) {
                List<String> empIdList = staffIds.stream().map(StaffVO::getEmpInfoId).collect(Collectors.toList());
                Map<String, Boolean> whitelist = attendWhitelistService.isWhitelist(plan.getId(), empIdList, plan.getSiteId());
                for (StaffVO staffVO : staffIds) {
                    // 是否在白名单中
                    Boolean isWhitelist = whitelist.get(staffVO.getEmpInfoId());
                    if (isWhitelist) {
                        continue;
                    }
                    // 判断生效时间
                    if (plan.getTakeEffect() != null && plan.getTakeEffect() == 1 && plan.getStartEffectTime() != null
                            && DateKit8.addDays(plan.getStartEffectTime(), 1).getTime() > System.currentTimeMillis()) {
                        continue;
                    }
                    if (attendNeedPunchVO.getIsSpecialDate() && !attendNeedPunchVO.getIsNeedPunchOfDaily()) {
                        continue;
                    }
                    TokenUser tokenUser = new TokenUser();
                    tokenUser.setSiteId(plan.getSiteId());
                    // 考勤周
                    List<String> workWeekList = null;
                    // 考勤高级设置
                    AttendAdvancedDTO advanced = null;
                    // 查询公历表，日期类型 1休息日,2-工作日,3公假日
                    // 查询admin的公历记录，先查询租户的，租户的没有就查询默认的
                    org.jsola.admin.query.GregorianCalendarQuery gregorianCalendarQuery = new GregorianCalendarQuery();
                    String[] data = dateStr.split("-");
                    gregorianCalendarQuery.setYear(Integer.parseInt(data[0]));
                    gregorianCalendarQuery.setMonth(Integer.parseInt(data[1]));
                    gregorianCalendarQuery.setDay(Integer.parseInt(data[2]));
                    List<org.jsola.admin.entity.GregorianCalendarDO> gregorianCalendarDOList = gregorianCalendarProviderService
                            .selectClendar(gregorianCalendarQuery, tokenUser.getSiteId());
                    // 考勤规则类型- 固定时间上下班
                    if (plan.getPlanType().equals(RuleType.FIXED_TIME.getValue())) {
                        // 固定上下班的打卡时间
                        AttendRulePunchTimeAddDTO attendRulePunchTime = attendPunchTimeService.puncheTimeForFixed(plan.getId(), dateStr, tokenUser);
                        if (attendRulePunchTime == null) {
                            // 不是特殊日期  并且  不同步中国节假日   则直接跳过
                            boolean isContinue = !attendNeedPunchVO.getIsSpecialDate()
                                    && (plan.getIsSynchLegalHoliday() == null || !plan.getIsSynchLegalHoliday());
                            if (isContinue) {
                                continue;
                            } else if (!attendNeedPunchVO.getIsSpecialDate()) {
                                // 同步节假日
                                ParamException.isFalse(CollectionUtils.isEmpty(gregorianCalendarDOList),
                                        "同步中国节假日必须先同步日历信息!");
                                GregorianCalendarDO gregorianCalendarDO = gregorianCalendarDOList.get(0);
                                // 本日不是公历同步的信息 直接返回不需要打卡
                                if (!gregorianCalendarDO.getIsCalendar()) {
                                    continue;
                                }
                            }
                        }
                        else {
                            workWeekList = attendRulePunchTime.getWorkWeekList();
                            advanced = attendRulePunchTime.to(AttendAdvancedDTO.class);
                        }
                    }
                    // 按班次上下班
                    else if (plan.getPlanType().equals(RuleType.BY_SHIFT.getValue())) {
                        AttendShiftSaveDTO attendShift = attendShiftService.getAttendShift(plan.getId(), staffVO.getEmpInfoId(), dateStr, tokenUser);
                        if (attendShift == null) {
                            continue;
                        }
                        else {
                            advanced = attendShift.to(AttendAdvancedDTO.class);
                        }
                    }
                    // 自由上下班
                    else if (plan.getPlanType().equals(RuleType.FREE_WORK.getValue())) {
                        // 查询打卡工作周
                        workWeekList = attendPunchTimeService.getFreeWork(plan.getId(), dateStr, tokenUser);
                        if (workWeekList == null) {
                            continue;
                        }
                    }

                    // 不是特殊日期 并且 同步中国节假日
                    if (!attendNeedPunchVO.getIsSpecialDate() && plan.getIsSynchLegalHoliday() != null && plan.getIsSynchLegalHoliday()) {
                        if (gregorianCalendarDOList.size() > 0 && gregorianCalendarDOList.get(0).getIsCalendar()) {
                            org.jsola.admin.entity.GregorianCalendarDO gregorianCalendarDO = gregorianCalendarDOList.get(0);
                            // 日期类型 1休息日,2-工作日,3公假日
                            if (gregorianCalendarDO.getDateType() == 2) {
                                // 查询考勤时间段
                                // 根据考勤规则ID查询考勤打卡时间(hr_attend_punch_time)
                                AttendPunchTimeQuery attendPunchTimeQuery = new AttendPunchTimeQuery();
                                attendPunchTimeQuery.setAttendPlanId(plan.getId());
                                List<AttendPunchTimeDO> attendPunchTimeList = attendPunchTimeService.selectDO(attendPunchTimeQuery, tokenUser.getSiteId());
                                if (CollectionUtils.isEmpty(attendPunchTimeList)) {
                                    throw new ParamException("当前考勤规则没有设置时间段!");
                                }
                                AttendRulePunchTimeAddDTO attendRulePunchTime = attendPunchTimeList.get(0).to(AttendRulePunchTimeAddDTO.class);
                                attendRulePunchTime.setWorkWeekList(workWeekList);
                                attendRulePunchTime.setPeriodList(JSON.parseArray(attendPunchTimeList.get(0).getPeriodJson(), AttendPeriodDTO.class));
                                attendRulePunchTime.setAttendPunchTimeId(attendPunchTimeList.get(0).getId());
                            }
                            else if (gregorianCalendarDO.getDateType() == 1 || gregorianCalendarDO.getDateType() == 3){
                                continue;
                            }
                        }
                    }
                    // 上班打卡标准时间
                    String startPeriod = "";
                    // 下班打卡标准时间
                    String endPeriod = "";
                    // 根据考勤规则ID查询考勤打卡时间(hr_attend_punch_time)
                    AttendPunchTimeQuery attendPunchTimeQuery = new AttendPunchTimeQuery();
                    attendPunchTimeQuery.setAttendPlanId(plan.getId());
                    List<AttendPunchTimeDO> attendPunchTimeList = attendPunchTimeService.selectDO(attendPunchTimeQuery, tokenUser.getSiteId());
                    if (!CollectionUtils.isEmpty(attendPunchTimeList)) {
                        List<AttendPeriodDTO> attendPeriodDTOList = JSON.parseArray(attendPunchTimeList.get(0).getPeriodJson(), AttendPeriodDTO.class);
                        if(!CollectionUtils.isEmpty(attendPeriodDTOList)){
                            for (AttendPeriodDTO attendPeriodDTO : attendPeriodDTOList) {
                                startPeriod = attendPeriodDTO.getStartPeriod();
                                endPeriod = attendPeriodDTO.getEndPeriod();
                                DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                                String onWorkStandardTime = null;
                                String offWorkStandardTime = null;
                                onWorkStandardTime = df.format(df.parse(yesterdayStr + " " + startPeriod + ":00"));
                                offWorkStandardTime = df.format(df.parse(yesterdayStr + " " + endPeriod + ":00"));
                                List<String> standardTimeLst = new ArrayList<>();
                                standardTimeLst.add(onWorkStandardTime);
                                standardTimeLst.add(offWorkStandardTime);
                                // 查询每一个考勤时间点是否有打卡记录
                                AttendPunchRecordQuery attendPunchRecordQuery = new AttendPunchRecordQuery();
                                attendPunchRecordQuery.setAttendPlanId(plan.getId());
                                attendPunchRecordQuery.setEmpInfoId(staffVO.getEmpInfoId());
                                attendPunchRecordQuery.setYear(yearly);
                                attendPunchRecordQuery.setMonth(monthly);
                                attendPunchRecordQuery.setDay(daily);
                                attendPunchRecordQuery.setStandardTimeLst(standardTimeLst);
                                List<AttendPunchRecordDO> attendPunchRecordList = attendPunchRecordService.selectDO(attendPunchRecordQuery, plan.getSiteId());
                                if(CollectionUtils.isEmpty(attendPunchRecordList)){
                                    // 无打卡记录，先查询是不是更换了规则
                                    attendPunchRecordQuery.setAttendPlanId(null);
                                    attendPunchRecordQuery.setStandardTimeLst(null);
                                    attendPunchRecordList = attendPunchRecordService.selectDO(attendPunchRecordQuery, plan.getSiteId());
                                    if (!CollectionUtils.isEmpty(attendPunchRecordList)) {
                                        // 使用老的规则给该人员生成缺卡记录
                                        Example exampleOne = new Example(AttendPlanDO.class);
                                        exampleOne.and()
                                                .andEqualTo("id", attendPunchRecordList.get(0).getAttendPlanId());
                                        AttendPlanDO attendPlanDO = attendPlanDAO.selectOneByExample(exampleOne);
                                        generateOldLackRecord(attendPlanDO, tokenUser, yesterdayStr,
                                                staffVO, yearly, monthly, daily, dateStr);
                                        // 该人员使用旧的规则 新规则跳过
                                        break;
                                    }
                                    // 无打卡记录，上班下班都缺卡
                                    AttendPointTimeVO onWorkPoint = new AttendPointTimeVO();
                                    onWorkPoint.setPointTime(startPeriod);
                                    onWorkPoint.setType(3);
                                    AttendPunchRecordDO attendPunchRecordDO = this.getAttendPunchRecord(plan, staffVO, dateStr, onWorkPoint);
                                    attendPunchRecordDAO.insert(attendPunchRecordDO);
                                    AttendPointTimeVO offWorkPoint = new AttendPointTimeVO();
                                    offWorkPoint.setPointTime(endPeriod);
                                    offWorkPoint.setType(4);
                                    AttendPunchRecordDO attendPunchRecordOffDO = this.getAttendPunchRecord(plan, staffVO, dateStr, offWorkPoint);
                                    attendPunchRecordDAO.insert(attendPunchRecordOffDO);
                                }else{
                                    // 有打卡记录，判断是否存在上班打卡或下班打卡
                                    boolean onWorkCheck = attendPunchRecordList.stream().anyMatch(item -> PunchType.ON_WORK.getValue().equals(item.getPunchType()) || PunchType.COMPLETE.getValue().equals(item.getPunchType()));
                                    if(!onWorkCheck){
                                        // 无上班打卡记录
                                        AttendPointTimeVO onWorkPoint = new AttendPointTimeVO();
                                        onWorkPoint.setPointTime(startPeriod);
                                        onWorkPoint.setType(3);
                                        AttendPunchRecordDO attendPunchRecordDO = this.getAttendPunchRecord(plan, staffVO, dateStr, onWorkPoint);
                                        attendPunchRecordDAO.insert(attendPunchRecordDO);
                                    }
                                    boolean offWorkCheck = attendPunchRecordList.stream().anyMatch(item -> PunchType.OFF_WORK.getValue().equals(item.getPunchType()) || PunchType.INVALID_PUNCH.getValue().equals(item.getPunchType()));
                                    if(!offWorkCheck){
                                        // 无下班打卡记录
                                        AttendPointTimeVO offWorkPoint = new AttendPointTimeVO();
                                        offWorkPoint.setPointTime(endPeriod);
                                        offWorkPoint.setType(4);
                                        AttendPunchRecordDO attendPunchRecordOffDO = this.getAttendPunchRecord(plan, staffVO, dateStr, offWorkPoint);
                                        attendPunchRecordDAO.insert(attendPunchRecordOffDO);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 打卡人员月统计 - 上班缺卡次数，下班缺卡次数
     */
    private void statPeopleMonthlyLack(AttendPunchRecordDO attendPunchRecordDO, String period, String siteId) {

        AttendPeopleMonthlyStatQuery attendPeopleMonthlyStatQuery = new AttendPeopleMonthlyStatQuery();
        attendPeopleMonthlyStatQuery.setCompanyId(attendPunchRecordDO.getCompanyId());
        attendPeopleMonthlyStatQuery.setEmpInfoId(attendPunchRecordDO.getEmpInfoId());
        attendPeopleMonthlyStatQuery.setAttendPlanId(attendPunchRecordDO.getAttendPlanId());
        attendPeopleMonthlyStatQuery.setYearly(attendPunchRecordDO.getYear());
        attendPeopleMonthlyStatQuery.setMonthly(attendPunchRecordDO.getMonth());
        List<AttendPeopleMonthlyStatDO> attendPeopleMonthlyStatList = attendPeopleMonthlyStatService.selectDO(attendPeopleMonthlyStatQuery, siteId);
        if (attendPeopleMonthlyStatList.size() > 0) {

            String peopleMonthlyStatId = attendPeopleMonthlyStatList.get(0).getId();

            AttendPeopleMonthlyStatDO attendPeopleMonthlyStatDO = new AttendPeopleMonthlyStatDO();
            attendPeopleMonthlyStatDO.setId(attendPeopleMonthlyStatList.get(0).getId());
            // 打卡类型 ; 0-缺卡,1-上班打卡,2-下班打卡
            if (attendPunchRecordDO.getPunchType() == 1) {
                attendPeopleMonthlyStatDO.setOnWorkMissCounts(attendPeopleMonthlyStatList.get(0).getOnWorkMissCounts() + 1);
            }
            else if (attendPunchRecordDO.getPunchType() == 2) {
                attendPeopleMonthlyStatDO.setOffWorkMissCounts(attendPeopleMonthlyStatList.get(0).getOffWorkMissCounts() + 1);
            }

            attendPeopleMonthlyStatDAO.updateByPrimaryKeySelective(attendPeopleMonthlyStatDO);

            // 考勤打卡时间段统计
            // hr_attend_period_stat
            AttendPeriodStatDO attendPeriodStatDO = new AttendPeriodStatDO();
            attendPeriodStatDO.setId(UUID.randomUUID().toString().replace("-", ""));
            attendPeriodStatDO.setPeopleMonthlyStatId(peopleMonthlyStatId);
            attendPeriodStatDO.setCompanyId(attendPunchRecordDO.getCompanyId());
            attendPeriodStatDO.setAttendPlanId(attendPunchRecordDO.getAttendPlanId());
            attendPeriodStatDO.setEmpInfoId(attendPunchRecordDO.getEmpInfoId());
            attendPeriodStatDO.setAttendPunchTimeId("");
            attendPeriodStatDO.setPeriod(period);
            attendPeriodStatDO.setYearly(attendPunchRecordDO.getYear());
            attendPeriodStatDO.setMonthly(attendPunchRecordDO.getMonth());
            attendPeriodStatDO.setAttendRecordId(attendPunchRecordDO.getId());
            attendPeriodStatDO.setCreateUserId("");
            attendPeriodStatDO.setGmtCreate(new Date());
            attendPeriodStatDO.setModifiedUserId("");
            attendPeriodStatDO.setGmtModified(new Date());
            attendPeriodStatDO.setSiteId(attendPunchRecordDO.getSiteId());
            attendPeriodStatDO.setValid(true);

            attendPeriodStatDAO.insert(attendPeriodStatDO);
        }
        // hr_attend_people_monthly_stat
    }

    /**
     * 缺卡的打卡记录
     *
     * @param plan
     * @param staffVO
     * @param dateStr
     * @param attendPointTimeVO
     * @return
     */
    private AttendPunchRecordDO getAttendPunchRecord(AttendPlanDO plan, StaffVO staffVO, String dateStr, AttendPointTimeVO attendPointTimeVO) {

        // 查询员工所在部门
        DepInfoDO depInfo = this.getDepInfo(staffVO.getEmpInfoId(), plan.getSiteId());

        AttendPunchRecordDO attendPunchRecordDO = new AttendPunchRecordDO();

        attendPunchRecordDO.setId(UUID.randomUUID().toString().replace("-", ""));
        // 公司ID
        attendPunchRecordDO.setCompanyId(plan.getCompanyId());
        // 公司名称
        attendPunchRecordDO.setCompanyName(plan.getCompanyName());
        // 部门ID
        attendPunchRecordDO.setDeptId(depInfo != null ? depInfo.getId() : "");
        // 部门名称
        attendPunchRecordDO.setDeptName(depInfo != null ? depInfo.getName() : "");
        // 员工ID
        attendPunchRecordDO.setEmpInfoId(staffVO.getEmpInfoId());
        // 员工姓名
        attendPunchRecordDO.setEmpInfoName(staffVO.getEmpInfoName());
        // 考勤方案
        attendPunchRecordDO.setAttendPlanId(plan.getId());
        // 考勤方案名称
        attendPunchRecordDO.setAttendPlanName(plan.getName());
        // 年度
        attendPunchRecordDO.setYear(dateStr.split("-")[0]);
        // 月
        attendPunchRecordDO.setMonth(dateStr.split("-")[1]);
        // 日
        attendPunchRecordDO.setDay(dateStr.split("-")[2]);
        // 打卡类型（1：上班打卡，2：下班打卡，3：上班缺卡，4：下班缺卡）
        attendPunchRecordDO.setPunchType(attendPointTimeVO.getType());
        if (Objects.nonNull(attendPointTimeVO)) {
            // 标准时间
            attendPunchRecordDO.setStandardTime(DateKit.getDate("HH:mm", attendPointTimeVO.getPointTime()));
        }
        else {
//            attendPunchRecordDO.setStandardTime("00:00");
//            attendPunchRecordDO.setPunchTime("00:00");
        }
        // 打卡时间(HH:mm)
        attendPunchRecordDO.setPunchTime(null);
        // 打卡状态 ; 0-无效打卡,1-正常,2-迟到,3-早退
        attendPunchRecordDO.setPunchStatus(0);
        // 迟到/早退分钟数
        attendPunchRecordDO.setMinute(0);
        // 判定描述
        attendPunchRecordDO.setDecisionDesc("");
        // 打卡坐标
        attendPunchRecordDO.setCoordinate("");
        // 打卡地点
        attendPunchRecordDO.setLocation("");
        // 打卡wifi
        attendPunchRecordDO.setPunchWifi("");
        // 打卡来源 ; 1-app打卡,2-考勤机打卡,3-Excel导入
        attendPunchRecordDO.setPunchSource(1);
        // 是否补卡 ; 1-是,0-否
        attendPunchRecordDO.setIsMakeUp(false);
        attendPunchRecordDO.setCreateUserId("");
        attendPunchRecordDO.setGmtCreate(new Date());
        attendPunchRecordDO.setModifiedUserId("");
        attendPunchRecordDO.setGmtModified(new Date());
        attendPunchRecordDO.setSiteId(plan.getSiteId());
        attendPunchRecordDO.setValid(true);

        return attendPunchRecordDO;
    }

    /**
     * 从打卡人员当中获取打卡人员
     */
    private Set<StaffVO> getStaffSetForPunchStaff(String attendPlanId, String siteId) {
        Set<StaffVO> staffIds = new HashSet<>();
        // 查询考勤打卡参与人员
        AttendPunchStaffQuery attendPunchStaffQuery = new AttendPunchStaffQuery();
        attendPunchStaffQuery.setAttendPlanId(attendPlanId);
        List<AttendPunchStaffDO> staffList = attendPunchStaffService.selectDO(attendPunchStaffQuery, siteId);
        if (!CollectionUtils.isEmpty(staffList)) {
            for (AttendPunchStaffDO attendPunchStaff : staffList) {
                StaffVO staffVO = new StaffVO();
                staffVO.setEmpInfoId(attendPunchStaff.getEmpInfoId());
                staffVO.setEmpInfoName(attendPunchStaff.getEmpInfoName());
                staffIds.add(staffVO);
            }
        }

        return staffIds;
    }

    /**
     * 从考勤部门当中获取打卡人员
     * @return
     */
    private Set<StaffVO> getStaffSetForPunchDep(String attendPlanId, String siteId) {
        Set<StaffVO> staffIds = new HashSet<>();
        // 查询考勤打卡参与部门
        AttendPunchDeptQuery attendPunchDeptQuery = new AttendPunchDeptQuery();
        attendPunchDeptQuery.setAttendPlanId(attendPlanId);
        List<AttendPunchDeptDO> deptList = attendPunchDeptService.selectDO(attendPunchDeptQuery, siteId);
        if (!CollectionUtils.isEmpty(deptList)) {
            List<String> depIdList = deptList.stream().map(AttendPunchDeptDO::getDeptId).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(depIdList)){
                List<String> empIdList = empDepService.selectEmpIdListByDepId(depIdList, new EmpDepQuery(), siteId);
                if(!CollectionUtils.isEmpty(empIdList)){
                    List<EmpInfoDO> empInfoList = empInfoService.selectDoByIds(empIdList);
                    for (EmpInfoDO empInfo : empInfoList) {
                        StaffVO staffVO = new StaffVO();
                        staffVO.setEmpInfoId(empInfo.getId());
                        staffVO.setEmpInfoName(empInfo.getName());
                        staffIds.add(staffVO);
                    }
                }
            }
        }

        return staffIds;
    }

    private DepInfoDO getDepInfo(String empInfoId, String siteId) {

        DepInfoDO depInfoDO = null;

        EmpDepQuery empDepQuery = new EmpDepQuery();
        empDepQuery.setEmpId(empInfoId);
        List<EmpDepDO> empDepList = empDepService.selectDO(empDepQuery, siteId);
        if (empDepList.size() <= 0) {
            return depInfoDO;
        }

        // 查询部门信息
        depInfoDO = depInfoService.selectDOById(empDepList.get(0).getDepId(), siteId);

        return depInfoDO;
    }

    /**
     * 根据规则 生成对应的缺卡记录
     * @param attendPlanDO
     * @param tokenUser
     * @param yesterdayStr
     * @param staffVO
     * @param yearly
     * @param monthly
     * @param daily
     * @param dateStr
     * @throws ParseException
     */
    private void generateOldLackRecord(AttendPlanDO attendPlanDO, TokenUser tokenUser, String yesterdayStr,
                                       StaffVO staffVO, String yearly, String monthly, String daily,
                                       String dateStr) throws ParseException {
        // 上班打卡标准时间
        String startPeriod = "";
        // 下班打卡标准时间
        String endPeriod = "";
        // 根据考勤规则ID查询考勤打卡时间(hr_attend_punch_time)
        List<AttendPunchTimeDO> attendPunchTimeList = attendPunchTimeService
                .selectDOByAttendPlanId(attendPlanDO.getId(), tokenUser.getSiteId());
        if (!CollectionUtils.isEmpty(attendPunchTimeList)) {
            List<AttendPeriodDTO> attendPeriodDTOList = JSON.parseArray(attendPunchTimeList.get(0).getPeriodJson(), AttendPeriodDTO.class);
            if(!CollectionUtils.isEmpty(attendPeriodDTOList)){
                for (AttendPeriodDTO attendPeriodDTO : attendPeriodDTOList) {
                    startPeriod = attendPeriodDTO.getStartPeriod();
                    endPeriod = attendPeriodDTO.getEndPeriod();
                    DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    String onWorkStandardTime = null;
                    String offWorkStandardTime = null;
                    onWorkStandardTime = df.format(df.parse(yesterdayStr + " " + startPeriod + ":00"));
                    offWorkStandardTime = df.format(df.parse(yesterdayStr + " " + endPeriod + ":00"));
                    List<String> standardTimeLst = new ArrayList<>();
                    standardTimeLst.add(onWorkStandardTime);
                    standardTimeLst.add(offWorkStandardTime);
                    // 查询每一个考勤时间点是否有打卡记录
                    AttendPunchRecordQuery attendPunchRecordQuery = new AttendPunchRecordQuery();
                    attendPunchRecordQuery.setAttendPlanId(attendPlanDO.getId());
                    attendPunchRecordQuery.setEmpInfoId(staffVO.getEmpInfoId());
                    attendPunchRecordQuery.setYear(yearly);
                    attendPunchRecordQuery.setMonth(monthly);
                    attendPunchRecordQuery.setDay(daily);
                    attendPunchRecordQuery.setStandardTimeLst(standardTimeLst);
                    List<AttendPunchRecordDO> attendPunchRecordList = attendPunchRecordService.selectDO(attendPunchRecordQuery, attendPlanDO.getSiteId());
                    if(CollectionUtils.isEmpty(attendPunchRecordList)){
                        // 无打卡记录，上班下班都缺卡
                        AttendPointTimeVO onWorkPoint = new AttendPointTimeVO();
                        onWorkPoint.setPointTime(startPeriod);
                        onWorkPoint.setType(3);
                        AttendPunchRecordDO attendPunchRecordDO = this.getAttendPunchRecord(attendPlanDO, staffVO, dateStr, onWorkPoint);
                        attendPunchRecordDAO.insert(attendPunchRecordDO);
                        AttendPointTimeVO offWorkPoint = new AttendPointTimeVO();
                        offWorkPoint.setPointTime(endPeriod);
                        offWorkPoint.setType(4);
                        AttendPunchRecordDO attendPunchRecordOffDO = this.getAttendPunchRecord(attendPlanDO, staffVO, dateStr, offWorkPoint);
                        attendPunchRecordDAO.insert(attendPunchRecordOffDO);
                    }else{
                        // 有打卡记录，判断是否存在上班打卡或下班打卡
                        Boolean onWorkCheck = attendPunchRecordList.stream().anyMatch(item -> PunchType.ON_WORK.getValue().equals(item.getPunchType()) || PunchType.COMPLETE.getValue().equals(item.getPunchType()));
                        if(!onWorkCheck){
                            // 无上班打卡记录
                            AttendPointTimeVO onWorkPoint = new AttendPointTimeVO();
                            onWorkPoint.setPointTime(startPeriod);
                            onWorkPoint.setType(3);
                            AttendPunchRecordDO attendPunchRecordDO = this.getAttendPunchRecord(attendPlanDO, staffVO, dateStr, onWorkPoint);
                            attendPunchRecordDAO.insert(attendPunchRecordDO);
                        }
                        Boolean offWorkCheck = attendPunchRecordList.stream().anyMatch(item -> PunchType.OFF_WORK.getValue().equals(item.getPunchType()) || PunchType.INVALID_PUNCH.getValue().equals(item.getPunchType()));
                        if(!offWorkCheck){
                            // 无下班打卡记录
                            AttendPointTimeVO offWorkPoint = new AttendPointTimeVO();
                            offWorkPoint.setPointTime(endPeriod);
                            offWorkPoint.setType(4);
                            AttendPunchRecordDO attendPunchRecordOffDO = this.getAttendPunchRecord(attendPlanDO, staffVO, dateStr, offWorkPoint);
                            attendPunchRecordDAO.insert(attendPunchRecordOffDO);
                        }
                    }
                }
            }
        }
    }

}
